/**
  ******************************************************************************
  * @file    USB_Device/CDC_Standalone/Src/usbd_cdc_interface.c
  * @author  MCD Application Team
  * @brief   Source file for USBD CDC interface
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2017 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under Ultimate Liberty license
  * SLA0044, the "License"; You may not use this file except in compliance with
  * the License. You may obtain a copy of the License at:
  *                             www.st.com/SLA0044
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------ */
#include "./usbd_cdc_vcp.h"
#include "usb_inner.h"
#include "bsp_usart6.h"

/* define */
#define CDC_POLLING_INTERVAL        1       //轮询周期，最大65ms，最小1ms
#define CDC_TX_BUFF_SIZE            128
#define CDC_RX_BUFF_SIZE            128



/* static var */

static uint8_t cdc_tx_buff[CDC_TX_BUFF_SIZE];
static uint8_t cdc_rx_buff[CDC_RX_BUFF_SIZE];


static USBD_CDC_LineCodingTypeDef cdc_line_coding = {
    .bitrate = 115200,          /* baud rate */
    .format = 0x00,             /* stop bits-1 */
    .paritytype = 0x00,         /* parity - none */
    .datatype = 0x08            /* nb. of bits 8 */
};

/* extern var */
void (*usbd_cdc_rx_handle)(uint8_t *data, const uint32_t len) = NULL;



/* static func */

void vcp_usart_config(void)
{
    USART_HandleTypeDef *usart6_handle;
    
    usart6_handle = bsp_usart6_get_handle();

    /* 停止位 */
    switch (cdc_line_coding.format)
    {
    case 0: usart6_handle->Init.StopBits = UART_STOPBITS_1; break;
    case 2: usart6_handle->Init.StopBits = UART_STOPBITS_2; break;
    default: usart6_handle->Init.StopBits = UART_STOPBITS_1; break;
    }

    /* 奇偶校验位 */
    switch (cdc_line_coding.paritytype)
    {
    case 0: usart6_handle->Init.Parity = UART_PARITY_NONE; break;
    case 1: usart6_handle->Init.Parity = UART_PARITY_ODD; break;
    case 2: usart6_handle->Init.Parity = UART_PARITY_EVEN; break;
    default: usart6_handle->Init.Parity = UART_PARITY_NONE; break;
    }

    /* 数据位宽 */
    switch (cdc_line_coding.datatype)
    {
    case 0x07: usart6_handle->Init.WordLength = UART_WORDLENGTH_8B; break;
    case 0x08:
        if (usart6_handle->Init.Parity == UART_PARITY_NONE)
        {
            usart6_handle->Init.WordLength = UART_WORDLENGTH_8B;
        }
        else
        {
            usart6_handle->Init.WordLength = UART_WORDLENGTH_9B;
        }
        break;
    default: usart6_handle->Init.WordLength = UART_WORDLENGTH_8B; break;
    }

    usart6_handle->Init.BaudRate = cdc_line_coding.bitrate;
    usart6_handle->Init.Mode = UART_MODE_TX_RX;

    if (HAL_USART_Init(usart6_handle) != HAL_OK)
    {
    }
}

static int8_t vcp_if_init(void)
{
    USBD_HandleTypeDef *pdev;

    pdev = usbd_get_handle();
    USBD_CDC_SetTxBuffer(pdev, cdc_tx_buff, CDC_TX_BUFF_SIZE);
    USBD_CDC_SetRxBuffer(pdev, cdc_rx_buff);

    return (USBD_OK);
}

static int8_t vcp_if_deinit(void)
{
    return (USBD_OK);
}

static int8_t vcp_if_control(uint8_t cmd, uint8_t *pbuf, uint16_t length)
{
    switch (cmd)
    {
    case CDC_SEND_ENCAPSULATED_COMMAND: break;
    case CDC_GET_ENCAPSULATED_RESPONSE: break;
    case CDC_SET_COMM_FEATURE: break;
    case CDC_GET_COMM_FEATURE: break;
    case CDC_CLEAR_COMM_FEATURE: break;

    case CDC_SET_LINE_CODING:
        cdc_line_coding.bitrate = (uint32_t)(pbuf[0] | (pbuf[1] << 8) | (pbuf[2] << 16) | (pbuf[3] << 24));
        cdc_line_coding.format = pbuf[4];
        cdc_line_coding.paritytype = pbuf[5];
        cdc_line_coding.datatype = pbuf[6];

        /* Set the new configuration */
        // vcp_usart_config();
        break;

    case CDC_GET_LINE_CODING:
        pbuf[0] = (uint8_t)(cdc_line_coding.bitrate);
        pbuf[1] = (uint8_t)(cdc_line_coding.bitrate >> 8);
        pbuf[2] = (uint8_t)(cdc_line_coding.bitrate >> 16);
        pbuf[3] = (uint8_t)(cdc_line_coding.bitrate >> 24);
        pbuf[4] = cdc_line_coding.format;
        pbuf[5] = cdc_line_coding.paritytype;
        pbuf[6] = cdc_line_coding.datatype;
        break;

    case CDC_SET_CONTROL_LINE_STATE: break;
    case CDC_SEND_BREAK: break;
    default: break;
    }

    return (USBD_OK);
}

static int8_t vcp_if_receive(uint8_t *pbuf, uint32_t *len)
{
    USBD_HandleTypeDef *pdev;

    pdev = usbd_get_handle();
    USBD_CDC_ReceivePacket(pdev);
    if (usbd_cdc_rx_handle)
    {
        usbd_cdc_rx_handle(pbuf, (uint32_t)(*len));
    }
    memset(cdc_rx_buff, 0x00, sizeof(cdc_rx_buff));

    return (USBD_OK);
}

/* inner */

USBD_CDC_ItfTypeDef USBD_CDC_VCP_fops = {
    .Init = vcp_if_init,
    .DeInit = vcp_if_deinit,
    .Control = vcp_if_control,
    .Receive = vcp_if_receive,
};

void usbd_vcp_send_data(uint8_t *data, uint32_t len)
{
    USBD_HandleTypeDef *pdev;

    pdev = usbd_get_handle();
    USBD_CDC_SetTxBuffer(pdev, data, len);
    USBD_CDC_TransmitPacket(pdev);
    USBD_LL_Delay(CDC_POLLING_INTERVAL);
}

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
